﻿using Chat.Common;
using SuperSocket.ClientEngine;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ChatClient
{
    public partial class MainWindow : Form
    {

        private AsyncTcpSession client;

        public MainWindow()
        {
            InitializeComponent();
            CheckForIllegalCrossThreadCalls = false;
        }

        private void bConnect_Click(object sender, EventArgs e)
        {
            if (client != null)
            {
                client.Close();
                client = null;
            }

            if (bConnect.Text == "Disconnect")
            {
                bConnect.Text = "Connect";
                return;
            }

            try
            {
                client = new AsyncTcpSession(new IPEndPoint(IPAddress.Parse(tServer.Text), Convert.ToInt32(tPort.Value)));
                #region // bind events
                client.Closed += client_Closed;
                client.Connected += client_Connected;
                client.DataReceived += client_DataReceived;
                client.Error += client_Error;
                #endregion
                AppendMessage("Connecting...");
                bConnect.Text = "Disconnect";
                client.Connect();
            }
            catch (Exception ex)
            {
                AppendMessage("Connect failed", Environment.NewLine, ex.Message);
            }
        }

        void client_DataReceived(object sender, DataEventArgs e)
        {
            /// 这里要注意：
            /// e.Length 是实际数据的长度
            /// 如果直接使用 Encoding.UTF8.GetString(e.Data) 
            /// 会读取到填充的\0字符，这会引起不可预知的意外
            string data = Encoding.UTF8.GetString(e.Data, 0, e.Length);
            data = Base64.Decode(data);
            ResultStatus rs = JSON.DecodeObject<ResultStatus>(data);

            switch (rs.Type)
            {
                case ResultType.JOIN_RESULT: // 加入结果
                    // 加入成功
                    if (rs.Success)
                    {
                        if (!string.IsNullOrWhiteSpace(rs.Data))
                        {
                            list.Items.Clear();
                            string[] onlineusers = rs.Data.Split(",".ToArray());
                            if (onlineusers != null)
                            {
                                foreach (var item in onlineusers)
                                {
                                    AddUser(item);
                                }
                            }
                        }
                    }
                    else
                    {
                        client.Close();
                        bConnect.Text = "Connect";
                    }

                    AppendMessage(rs.Message);
                    break;
                case ResultType.NEW_JOIN: // 有新用户加入                    
                    AppendMessage(rs.Message);
                    AddUser(rs.Data.ToString());
                    break;
                case ResultType.SEND: // 发送消息结果
                    if (!rs.Success)
                    {
                        AppendMessage(rs.Message);
                    }
                    break;
                case ResultType.RECEIVE: // 收到消息
                    AppendMessage(rs.Message);
                    break;
                case ResultType.QUIT: // 用户退出
                    AppendMessage(rs.Message);
                    RemoveUser(rs.Data.ToString());
                    break;
            }
        }

        void client_Error(object sender, ErrorEventArgs e)
        {
            AppendMessage("Error:" + e.Exception.Message);
        }

        void client_Connected(object sender, EventArgs e)
        {
            AppendMessage("Connected. Asking for join...");
            SendCmd(CMD.JOIN, tName.Text);
        }

        void client_Closed(object sender, EventArgs e)
        {
            AppendMessage("Disconnected.");
            list.Items.Clear();
        }


        string cmdFormat = "{0} {1}\r\n";
        /// <summary>
        /// 向服务器发送命令行协议数据(此函数会将数据以Base64[UTF-8]方式编码，在服务器读取后，需要解码使用)
        /// </summary>
        /// <param name="cmd">请求的命令 <c>CMD</c></param>
        /// <param name="data">数据</param>
        void SendCmd(CMD cmd, params string[] data)
        {
            string body = string.Join("", data);
            body = Base64.Encode(body);

            // 完整命令数据
            string cmdData = string.Format(cmdFormat, cmd.ToString(), body);

            // 转换成字节数组
            byte[] byteData = Encoding.UTF8.GetBytes(cmdData);

            client.Send(byteData, 0, byteData.Length);
        }

        /// <summary>
        /// 追加日志和历史记录
        /// </summary>
        /// <param name="args"></param>
        private void AppendMessage(params string[] args)
        {
            string msg = "";
            if (args != null)
            {

                foreach (var item in args)
                {
                    msg += item;
                }
                msg += Environment.NewLine;
            }
            tHistory.AppendText(msg);
            tHistory.ScrollToCaret();
        }

        private void bSend_Click(object sender, EventArgs e)
        {
            string msg = tMessage.Text;

            if (list.Items.Count == 0)
            {
                MessageBox.Show(this, "No user online.");
                return;
            }

            AppendMessage("[You said]:", msg);
            tMessage.Clear();

            var selected = list.SelectedItems;
            if (selected.Count == 0)
            {
                SendCmd(CMD.ONE2ALL, msg);
            }
            else
            {
                SendCmd(CMD.ONE2ONE, selected[0].Text, msg);
            }

            byte[] data = Encoding.UTF8.GetBytes(msg);
            client.Send(data, 0, data.Length);
        }

        public void AddUser(string name)
        {
            Invoke((MethodInvoker)delegate()
            {
                var row = new ListViewItem(new string[] { name });


                list.Items.Add(row);
            });
        }

        public void RemoveUser(string name)
        {
            Invoke((MethodInvoker)delegate()
            {
                ListViewItem item = null;
                foreach (ListViewItem row in list.Items)
                {
                    if (row.Text == name)
                    {
                        item = row;
                        break;
                    }
                }
                if (item != null)
                {
                    list.Items.Remove(item);
                }
            });
        }

        private void MainWindow_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (client != null)
            {
                if (client.IsConnected)
                {
                    client.Close();
                }
                client = null;
            }
        }
    }
}
